﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Windows;
using System.Runtime.InteropServices;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Threading;
using System.Linq;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Media.Imaging;
using JiveMessenger.Utilities;
using JiveMessenger.AvalonEdit;
using ICSharpCode.AvalonEdit;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Media.Animation;

namespace JiveMessenger
{
    public static class Extension
    {
        public static void Animate(this DependencyObject target, double from, double to,
          PropertyPath propertyPath, int duration, int startTime,
          EasingFunctionBase easing = null, Action completed = null)
        {
            Animate(target, from, to, propertyPath, duration, startTime, FillBehavior.HoldEnd, easing, completed);
        }

        public static void Animate(this DependencyObject target, double from, double to,
                          PropertyPath propertyPath, int duration, int startTime, FillBehavior fillBehavior,
                          EasingFunctionBase easing = null, Action completed = null)
        {
            if (easing == null)
            {
                easing = new SineEase();
            }

            var db = new DoubleAnimation();

            db.To = to;
            db.From = from;
            db.EasingFunction = easing;
            db.Duration = TimeSpan.FromMilliseconds(duration);
            Storyboard.SetTarget(db, target);
            Storyboard.SetTargetProperty(db, propertyPath);

            var sb = new Storyboard();
            sb.BeginTime = TimeSpan.FromMilliseconds(startTime);

            if (completed != null)
            {
                sb.Completed += (s, e) => completed();
            }
            sb.FillBehavior = fillBehavior;
            sb.Children.Add(db);

            sb.Begin();
        }

        public static void Remove<TK, TS>(this ConcurrentDictionary<TK, TS> dic, TK key)
        {
            TS obj = Activator.CreateInstance<TS>();

            dic.TryRemove(key, out obj);
        }

        public static byte[] ToByteArray(this FileInfo imgFile)
        {
            try
            {
                using (var stream = imgFile.OpenRead())
                {
                    BitmapDecoder streamBitmap = BitmapDecoder.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.Default);
                    BitmapEncoder encoder = null;
                    switch (streamBitmap.CodecInfo.FriendlyName)
                    {
                        default:
                        case "JPEG Decoder":
                            encoder = new JpegBitmapEncoder();
                            break;
                        case "PNG Decoder":
                            encoder = new PngBitmapEncoder();
                            break;
                        case "TIFF Decoder":
                            encoder = new TiffBitmapEncoder();
                            break;
                        case "BMP Decoder":
                            encoder = new BmpBitmapEncoder();
                            break;
                        case "GIF Decoder":
                            encoder = new GifBitmapEncoder();
                            break;
                    }
                    byte[] data;
                    encoder.Frames.Add(streamBitmap.Frames.FirstOrDefault());
                    using (MemoryStream ms = new MemoryStream())
                    {
                        encoder.Save(ms);
                        data = ms.ToArray();
                    }
                    return data;
                }
            }
            catch
            {
                return null;
            }
        }
        public static byte[] ToByteArray(this BitmapSource img)
        {

            byte[] data;
            PngBitmapEncoder encoder = new PngBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(img));
            using (MemoryStream ms = new MemoryStream())
            {
                encoder.Save(ms);
                data = ms.ToArray();
            }
            return data;
        }

        public static string GetMD5(this byte[] array)
        {
            using (var md5 = MD5.Create())
            {
                return BitConverter.ToString(md5.ComputeHash(array)).Replace("-", "").ToLower();
            }
        }
        public static string GetMD5(this FileInfo file)
        {
            using (var md5 = MD5.Create())
            {
                using (Stream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    return BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", "").ToLower();
                }
            }
        }

        public static List<int> AllIndexesOf(this string str, string value)
        {
            if (String.IsNullOrEmpty(value))
                throw new ArgumentException("the string to find may not be empty", "value");
            List<int> indexes = new List<int>();
            for (int index = 0; ; index += value.Length)
            {
                index = str.IndexOf(value, index, StringComparison.Ordinal);
                if (index == -1)
                    return indexes;
                indexes.Add(index);
            }
        }

        public static void AddRange<TK, TS>(this Dictionary<TK, TS> source, Dictionary<TK, TS> collection)
        {
            if (collection == null)
            {
                throw new ArgumentNullException("collection");
            }

            foreach (var item in collection)
            {
                if (!source.ContainsKey(item.Key))
                {
                    source.Add(item.Key, item.Value);
                }
            }
        }
    }

    public static class FrameworkExtensions
    {
        public static void DoWhenLoaded<T>(this T element, Action<T> action) where T : FrameworkElement
        {
            if (element.IsLoaded)
            {
                action(element);
            }
            else
            {
                RoutedEventHandler handler = null;
                handler = (sender, e) =>
                {
                    element.Loaded -= handler;
                    action(element);
                };
                element.Loaded += handler;
            }
        }
    }

    public static class ControlExtensions
    {
        public static void Invoke(this Dispatcher control, Action action)
        {
            try
            {
                control.Invoke(action);
            }
            catch (ObjectDisposedException) { }
        }

        public static void BeginInvoke(this Dispatcher control, Action action)
        {
            try
            {
                control.BeginInvoke(action);
            }
            catch (ObjectDisposedException) { }
        }
    }

    public static class WindowExtensions
    {
        #region Public Methods

        public static void FlashWindow(this Window win)
        {
            //Don't flash if the window is active
            //   if (win.IsActive) return;
            const uint count = 10;
            WindowInteropHelper h = new WindowInteropHelper(win);

            FLASHWINFO info = new FLASHWINFO
            {
                hwnd = h.Handle,
                dwFlags = Win32.FLASHW_ALL | Win32.FLASHW_TIMER,
                uCount = count,
                dwTimeout = 0
            };

            info.cbSize = Convert.ToUInt32(Marshal.SizeOf(info));
            Win32.FlashWindowEx(ref info);
        }

        public static void StopFlashingWindow(this Window win)
        {
            WindowInteropHelper h = new WindowInteropHelper(win);

            FLASHWINFO info = new FLASHWINFO();
            info.hwnd = h.Handle;
            info.cbSize = Convert.ToUInt32(Marshal.SizeOf(info));
            info.dwFlags = Win32.FLASHW_STOP;
            info.uCount = UInt32.MaxValue;
            info.dwTimeout = 0;

            Win32.FlashWindowEx(ref info);
        }
        #endregion
    }



    public static class EnumExtensionMethods
    {
        public static int GetIntValue(this Enum argEnum)
        {
            return Convert.ToInt32(argEnum);
        }
    }
}
